package com.jx.driving.message;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 请求报文
 * 
 * @author wuxiaozeng
 *
 */
public class Message implements Serializable {
	private static final long serialVersionUID = -5973957679081786766L;
	public static int DATA_LENGTH_PER_FRAME = 1023;
	private int identify = 0x7e;// 标识位
	private MessageHeader messageHeader;// 消息头
	private byte[] messageBody;// 消息体

	public Message() {
	}

	/**
	 * 构造方法，将byte转换成对象
	 */
	public Message(byte[] bytes) {
		this.messageHeader = new MessageHeader(bytes);
		int length = this.messageHeader.getMessageBodyProperty().getBodyLength();
		byte[] bodyByte = new byte[length];
		int bodyStart = 17;
		if (messageHeader.getMessageBodyProperty().getSubPackageFlag()) {
			bodyStart += 4;
		}
		System.arraycopy(bytes, bodyStart, bodyByte, 0, length);
		this.messageBody = bodyByte;
	}

	/**
	 * 得到报文 标识位 消息头 消息体 校验码 标识位
	 */
	public byte[] getMessageByteArray() {
		byte identifyByte = (byte) getIdentify();// 标识位
		byte[] headerByte = getMessageHeader().getMessageHeader(getMessageBody());
		byte[] messageBodyByte = getMessageBody();
		// 校验码，从消息头开始，同后一字节异或，直到校验码前一个字节，占用一个字节.暂时先不加
		byte checkCodeByte = (byte) (headerByte[0] ^ headerByte[1]);
		for (int i = 2; i < headerByte.length; i++) {
			checkCodeByte = (byte) (checkCodeByte ^ headerByte[i]);
		}
		for (int i = 0; i < messageBodyByte.length; i++) {
			checkCodeByte = (byte) (checkCodeByte ^ messageBodyByte[i]);
		}
		// 3表示两个标识和一个校验码
		int length = 3 + headerByte.length + messageBodyByte.length;
		byte[] newByte = new byte[length];
		newByte[0] = identifyByte;
		newByte[length - 2] = checkCodeByte;
		newByte[length - 1] = identifyByte;
		System.arraycopy(headerByte, 0, newByte, 1, headerByte.length);
		System.arraycopy(messageBodyByte, 0, newByte, 1 + headerByte.length, messageBodyByte.length);
		// 数据结束符
		return newByte;

	}

	/**
	 * 根据数据对象进行数据封装
	 */
	public static List<Message> getMessageList(byte[] data, int messageId, int sequence, String phone) {
		if (data.length == 0) {
			return Arrays.asList(getMessage(data, messageId, sequence, phone, false, 1, 1));
		}
		boolean splitPackage = true;
		int maxLengthPerPackage = DATA_LENGTH_PER_FRAME;
		int packageSum = 0;
		if (data.length <= maxLengthPerPackage) {
			splitPackage = false;
		} else {
			packageSum = (data.length % maxLengthPerPackage == 0) ? (data.length / maxLengthPerPackage)
					: (data.length / maxLengthPerPackage + 1);
		}
		List<Message> messageList = new ArrayList<>(data.length / maxLengthPerPackage + 1);
		int seq = sequence;
		for (int i = 0, index = 1; i < data.length; index++) {
			int to = Math.min((i + maxLengthPerPackage), data.length);
			byte[] split = Arrays.copyOfRange(data, i, to);
			messageList.add(getMessage(split, messageId, seq++, phone, splitPackage, index, packageSum));
			i = to;
		}
		return messageList;
	}

	public static Message getMessage(byte[] data, int messageId, int sequence, String phone, boolean splitPackage,
			int currentPackage, int sumPackage) {
		Message message = new Message();
		MessageHeader head = new MessageHeader();
		MessageBodyProperty property = new MessageBodyProperty();
		property.setBodyLength(data.length);
		property.setSubPackageFlag(splitPackage);
		head.setMessageBodyProperty(property);
		head.setPackageSum(sumPackage);
		head.setPackageNumber(currentPackage);
		head.setMessageId(messageId);
		head.setSeq(sequence);
		head.setPhone(phone);
		message.setMessageBody(data);
		message.setMessageHeader(head);
		return message;
	}

	public int getIdentify() {
		return identify;
	}

	public void setIdentify(int identify) {
		this.identify = identify;
	}

	public MessageHeader getMessageHeader() {
		return messageHeader;
	}

	public void setMessageHeader(MessageHeader messageHeader) {
		this.messageHeader = messageHeader;
	}

	public byte[] getMessageBody() {
		return messageBody;
	}

	public void setMessageBody(byte[] messageBody) {
		this.messageBody = messageBody;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + identify;
		result = prime * result + Arrays.hashCode(messageBody);
		result = prime * result + ((messageHeader == null) ? 0 : messageHeader.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Message other = (Message) obj;
		if (identify != other.identify)
			return false;
		if (!Arrays.equals(messageBody, other.messageBody))
			return false;
		if (messageHeader == null) {
			if (other.messageHeader != null)
				return false;
		} else if (!messageHeader.equals(other.messageHeader))
			return false;
		return true;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Message [identify=").append(identify).append(", messageHeader=").append(messageHeader)
				.append(", messageBody=").append(Arrays.toString(messageBody)).append("]");
		return builder.toString();
	}

}
